package math;

import math.visitors.ReplaceVisitor;
import java.util.List;
import math.visitors.CollectByTypeVisitor;

public class Rule {

  private Expression template;
  
  private Expression target;
  
  private String name;
  
  public Rule(String name, Expression template, Expression target){
    this.template = template;
    this.target = target;
    this.name = name;
  }
  
  public String getName() {
    return name;
  }
  
  public Expression getTemplate() {
    return template;
  }
  
  public Expression getTarget() {
    return target;
  }
  
  public boolean matches(Expression expr){
    reset();
    boolean result = template.matches(expr);
    return result;
  }
  
  public Expression apply(Expression expr){
    List<LogicalArithmeticVariable> aVars = template.accept(new CollectByTypeVisitor<LogicalArithmeticVariable>(LogicalArithmeticVariable.class));
    List<LogicalBooleanVariable> bVars = template.accept(new CollectByTypeVisitor<LogicalBooleanVariable>(LogicalBooleanVariable.class));
    List<Evaluation> evals = target.accept(new CollectByTypeVisitor<Evaluation>(Evaluation.class));
    Expression result = target;
    for (LogicalArithmeticVariable aVar: aVars){
      result = result.accept(new ReplaceVisitor(aVar, aVar.getValue()));
    }
    for (LogicalBooleanVariable bVar: bVars){
      result = result.accept(new ReplaceVisitor(bVar, bVar.getValue()));
    }
    for (Evaluation eval: evals){
      result = result.accept(new ReplaceVisitor(eval, eval.evaluate()));
    }
    return result;
  }
  
  private void reset(){
    List<LogicalArithmeticVariable> aVars = template.accept(new CollectByTypeVisitor<LogicalArithmeticVariable>(LogicalArithmeticVariable.class));
    for (LogicalArithmeticVariable aVar: aVars)
      aVar.reset();
    List<LogicalBooleanVariable> bVars = template.accept(new CollectByTypeVisitor<LogicalBooleanVariable>(LogicalBooleanVariable.class));
    for (LogicalBooleanVariable bVar: bVars)
      bVar.reset();
  }
  
  @Override
  public String toString() {
    return name + ": " + template + " --> " + target;
  }
}